package com.label.grade.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.label.grade.entity.Do.*;
import com.label.grade.entity.Do.Dictionary;
import com.label.grade.entity.Vo.ExtracurricularDetailVo;
import com.label.grade.entity.Vo.ExtracurricularOverallScoreVo;
import com.label.grade.entity.Vo.ExtracurricularScoreVo;
import com.label.grade.mapper.*;
import com.label.grade.service.ExtracurricularSumCalcService;
import com.label.grade.service.ExtracurricularSumCalcService;
import com.label.grade.utils.ExamSemesterCalculatorUtil;
import com.sun.codemodel.internal.JForEach;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;


import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhf
 * @description 针对表【EXTRACURRICULAR_SUM_CALC(学生成绩-二课成绩汇总信息表（由成绩表自行计算得出）)】的数据库操作Service实现
 * @createDate 2023-07-10 14:03:27
 */
@Service
public class ExtracurricularSumCalcServiceImpl extends ServiceImpl<ExtracurricularSumCalcMapper, ExtracurricularSumCalc>
        implements ExtracurricularSumCalcService {

    /**
     * @Description 每次直接重写学生二课成绩表所有数据，然后根据这个数据重新计算
     */

    @Resource
    private ExtracurricularScoreInfoMapper extracurricularScoreInfoMapper;

    @Resource
    private ExtracurricularInfoMapper extracurricularInfoMapper;

    @Resource
    private UndergraInfoMapper undergraInfoMapper;

    @Resource
    private ExtracurricularSumCalcMapper extracurricularSumCalcMapper;

    @Resource
    private DictionaryMapper dictionaryMapper;

    /**
     * @description 根据二课成绩计算二课汇总成绩生成表
     */
    @Override
    public void setExtracurricularSum() {
        //1 接口分页请求数据，请求一次处理一次

        //2 对比接口请求的数据与数据库数据 ，若是已有数据直接跳过，没有的数据更新

        //3 开始计算生成表 第二课堂成绩数据生成

        //3.1 先取出学生二课成绩数据中存在的所有学生
        List<Object> studentCodeObjectList = extracurricularScoreInfoMapper.selectObjs(new QueryWrapper<ExtracurricularScoreInfo>().lambda().select(ExtracurricularScoreInfo::getStudentCode));

        //要插入的实体list
        List<ExtracurricularSumCalc> extracurricularSumCalcList = new ArrayList<>();
        //3.2 obj -》 String
        List<String> studentCodeList = studentCodeObjectList.stream()
                .map(Object::toString) // 将每个元素转换为字符串
                .collect(Collectors.toList()); // 将结果收集到新的 List<String> 中
        //3.3 去重
        studentCodeList = studentCodeList.stream().distinct().collect(Collectors.toList());
        //3.4 取出每个单独学生进行处理
//        List<String> studentCodeList = new ArrayList<>();
//        studentCodeList.add("181370");
        studentCodeList.forEach(studentCode -> {

            System.out.println(studentCode);

            UndergraInfo undergraInfo = undergraInfoMapper.selectOne(new QueryWrapper<UndergraInfo>().lambda().eq(UndergraInfo::getStuNumber, studentCode));
            if (undergraInfo == null) return;

            //3.4.1 取出每个学生的所有第二课堂成绩数据
            List<ExtracurricularScoreInfo> extracurricularScoreInfos = extracurricularScoreInfoMapper.selectList(new QueryWrapper<ExtracurricularScoreInfo>().lambda().eq(ExtracurricularScoreInfo::getStudentCode, studentCode));
            //3.4.2 分学期处理，八个学期
            List<List<ExtracurricularScoreInfo>> SemesterExtracurricularScoreInfos = divideBySemester(extracurricularScoreInfos);
            for (int i = 0; i < 8; i++) {
                //3.4.2.1 对每学期的二课成绩进行处理
                List<ExtracurricularScoreInfo> semesterExtracurricularScoreInfo = SemesterExtracurricularScoreInfos.get(i);
                //3.4.2.3 先看这学期的二课数据是否存在，可能长度为0，处理可能报错，直接跳过
                if (!semesterExtracurricularScoreInfo.isEmpty()) {
                    //3.4.2.4 根据对应课程组 填充每个维度第二课堂数据
                    ExtracurricularSumCalc extracurricularSumCalc = fillExtracurricularDimensionDataByExtracurricularScoreInfos(semesterExtracurricularScoreInfo);
                    //3.4.2.5 填充其他基础信息

                    extracurricularSumCalc.setStudentName(undergraInfo.getStuName());
                    extracurricularSumCalc.setStudentCode(Long.valueOf(undergraInfo.getStuNumber()));
                    extracurricularSumCalc.setMajorLabel(undergraInfo.getMajor());
                    extracurricularSumCalc.setClassLabel(undergraInfo.getClassName());
                    extracurricularSumCalc.setCollegeLabel(undergraInfo.getCollege());

                    //3.4.2.6 填充学年学期
                    // 0 为 秋季学期 1 为 春季学期
                    extracurricularSumCalc.setSemester(String.valueOf(i % 2));
                    extracurricularSumCalc.setAcademicYear(String.valueOf(i / 2));

                    extracurricularSumCalcList.add(extracurricularSumCalc);

                }
            }
        });
        // TODO: 2023/7/12  策略：根据几个字段判断是否已有，存在则跳过不存在则更新
        // 4 成绩数据已经生成，更新（策略：根据几个字段判断是否已有，存在则跳过不存在则更新）
        extracurricularSumCalcList.forEach(extracurricularSumCalc -> {
            extracurricularSumCalcMapper.insert(extracurricularSumCalc);
        });


        return;

    }

    @Override
    public List<ExtracurricularOverallScoreVo> getExtracurricularOverallScore() {

        List<ExtracurricularOverallScoreVo> extracurricularOverallScoreList = extracurricularSumCalcMapper.listExtracurricularOverallScore();
        return extracurricularOverallScoreList;

    }

    @Override
    public ExtracurricularScoreVo getExtracurricularScore(String studentCode) {
        ExtracurricularScoreVo extracurricularScoreVo = extracurricularSumCalcMapper.selExtracurricularScore(studentCode);
        //2 获取所有维度数据
        List<ExtracurricularSumCalc> extracurricularSumCalcList = extracurricularSumCalcMapper.selectList(new QueryWrapper<ExtracurricularSumCalc>().lambda().eq(ExtracurricularSumCalc::getStudentCode, studentCode));
        //3 维度数据填充
        Map<String, ExtracurricularScoreVo.Semester> semesterMap = new HashMap<>();
        extracurricularSumCalcList.forEach(extracurricularSumCalc -> {
            //3.1 第一维度
            ExtracurricularScoreVo.DimensionOne dimensionOne = extracurricularScoreVo.new DimensionOne();
            dimensionOne.setAcademicTechnology(String.valueOf(extracurricularSumCalc.getAcademicTechnology()));
            dimensionOne.setPracticalService(String.valueOf(extracurricularSumCalc.getPracticalService()));
            dimensionOne.setIdealsBeliefs(String.valueOf(extracurricularSumCalc.getIdealsBeliefs()));
            dimensionOne.setLiteratureArt(String.valueOf(extracurricularSumCalc.getLiteratureArt()));
            dimensionOne.setPhysicalFitness(String.valueOf(extracurricularSumCalc.getPhysicalFitness()));
            dimensionOne.setSocialWork(String.valueOf(extracurricularSumCalc.getSocialWork()));
            //3.2 第二维度
            ExtracurricularScoreVo.DimensionTwo dimensionTwo = extracurricularScoreVo.new DimensionTwo();
            dimensionTwo.setAwardsHonors(String.valueOf(extracurricularSumCalc.getAwardsHonors()));
            dimensionTwo.setActivitiesCompetitions(String.valueOf(extracurricularSumCalc.getActivitiesCompetitions()));
            dimensionTwo.setStudentOrganization(String.valueOf(extracurricularSumCalc.getStudentOrganization()));
            //3.3 第三维度
            ExtracurricularScoreVo.DimensionThree dimensionThree = extracurricularScoreVo.new DimensionThree();
            dimensionThree.setCollegeLevel(String.valueOf(extracurricularSumCalc.getCollegeLevel()));
            dimensionThree.setNationalLevel(String.valueOf(extracurricularSumCalc.getNationalLevel()));
            dimensionThree.setProvincialLevel(String.valueOf(extracurricularSumCalc.getProvincialLevel()));
            dimensionThree.setUniversityLevel(String.valueOf(extracurricularSumCalc.getUniversityLevel()));
            //4 维度数据填充至Semester
            ExtracurricularScoreVo.Semester semeter = extracurricularScoreVo.new Semester();
            semeter.setDimensionOne(dimensionOne);
            semeter.setDimensionTwo(dimensionTwo);
            semeter.setDimensionThree(dimensionThree);
            semeter.setTotalGrade(extracurricularSumCalc.getOverallGrade());
            //5 临时map存储Map<String,Semester>
            String.valueOf(dictionaryMapper.selectObjs(new QueryWrapper<Dictionary>().lambda().select(Dictionary::getDicValue).eq(Dictionary::getLabel, "year").eq(Dictionary::getDicCode, extracurricularSumCalc.getAcademicYear())));
            dictionaryMapper.selectObjs(new QueryWrapper<Dictionary>().lambda().select(Dictionary::getDicValue).eq(Dictionary::getLabel, "semester").eq(Dictionary::getDicCode, extracurricularSumCalc.getSemester()));
            semesterMap.put(StringUtils.strip(dictionaryMapper.selectObjs(new QueryWrapper<Dictionary>().lambda().select(Dictionary::getDicValue).eq(Dictionary::getLabel, "year").eq(Dictionary::getDicCode, extracurricularSumCalc.getAcademicYear())).toString(), "[]") + StringUtils.strip(dictionaryMapper.selectObjs(new QueryWrapper<Dictionary>().lambda().select(Dictionary::getDicValue).eq(Dictionary::getLabel, "semester").eq(Dictionary::getDicCode, extracurricularSumCalc.getSemester())).toString(), "[]"), semeter);


        });
        //6 填充对象map
        extracurricularScoreVo.setSemester(semesterMap);


        return extracurricularScoreVo;
    }

    @Override
    public ExtracurricularDetailVo getExtracurricularDetail(String studentCode) {

        ExtracurricularDetailVo extracurricularDetailVo = new ExtracurricularDetailVo();



        //1 找到这个学生的所有二课成绩
        extracurricularScoreInfoMapper.selectList(new QueryWrapper<ExtracurricularScoreInfo>()
                        .lambda()
                        .eq(ExtracurricularScoreInfo::getStudentCode, studentCode)).stream()
                .forEach(extracurricularScoreInfo -> {
                    //2 遍历二课成绩
                    ExtracurricularDetailVo.ExtracurricularBasicInfo basicInfo ;
                    //2.1 只用二课成绩填充该信息
                    basicInfo = getBasicInfoByScore(extracurricularScoreInfo);
                    //2.2 这条成绩信息中的活动id不存在
                    if (extracurricularScoreInfo.getActivityCode() == null) {
                        extracurricularDetailVo.addOthers(basicInfo);
                        return;
                    }
                    //3 找对应的二课活动
                    ExtracurricularInfo extracurricularInfo = extracurricularInfoMapper.selectOne(new QueryWrapper<ExtracurricularInfo>().lambda().eq(ExtracurricularInfo::getActivityCode, extracurricularScoreInfo.getActivityCode()));
                    //3.1 对应的二课活动不存在
                    if(extracurricularInfo == null){
                        extracurricularDetailVo.addOthers(basicInfo);
                        return;
                    }
                    //4 存在对应活动,修改对应得级别
                    basicInfo.setActivityLevel(extracurricularInfo.getActivityLevel() != null ? extracurricularInfo.getActivityLevel() : "暂无");

                    String activityObjective = extracurricularInfo.getActivityObjective();
                    //4.1 不存在对应得活动目标
                    if(activityObjective == null || activityObjective.isEmpty()){
                        // 只用二课成绩填充该信息
                        extracurricularDetailVo.addOthers(basicInfo);
                        return;
                    }
                    //5 根据活动目标添加到对应得list
                    if(Objects.equals(activityObjective,"体育素质")){extracurricularDetailVo.addPhysicalFitness(basicInfo);}
                    else if(Objects.equals(activityObjective,"文化艺术")){extracurricularDetailVo.addLiteratureArt(basicInfo);}
                    else if(Objects.equals(activityObjective,"学术科技")){extracurricularDetailVo.addAcademicTechnology(basicInfo);}
                    else if(Objects.equals(activityObjective,"实践服务")){extracurricularDetailVo.addPracticalService(basicInfo);}
                    else if(Objects.equals(activityObjective,"社会工作")){extracurricularDetailVo.addSocialWork(basicInfo);}
                    else if(Objects.equals(activityObjective,"理想信念")){extracurricularDetailVo.addIdealsBeliefs(basicInfo);}
                    else{extracurricularDetailVo.addOthers(basicInfo);}

                });

        return extracurricularDetailVo;
    }

    /**
     * @param extracurricularScoreInfo
     * @return
     * @description 仅通过二课成绩填充二课基本信息
     */
    private ExtracurricularDetailVo.ExtracurricularBasicInfo getBasicInfoByScore(ExtracurricularScoreInfo extracurricularScoreInfo) {

        ExtracurricularDetailVo extracurricularDetailVo = new ExtracurricularDetailVo();

        ExtracurricularDetailVo.ExtracurricularBasicInfo basicInfo = extracurricularDetailVo.new ExtracurricularBasicInfo();
        basicInfo.setScore(extracurricularScoreInfo.getScore());
        basicInfo.setActivityLabel(extracurricularScoreInfo.getActivityLabel());
        basicInfo.setActivityLevel("暂无");
        basicInfo.setYearSemester(dictionaryMapper
                .selectOne(new QueryWrapper<Dictionary>()
                        .lambda()
                        .eq(Dictionary::getLabel, "year")
                        .eq(Dictionary::getDicCode, String.valueOf((ExamSemesterCalculatorUtil.
                                getYearSemester(extracurricularScoreInfo.getStudentCode().toString(), extracurricularScoreInfo.getYear(), extracurricularScoreInfo.getSemester())
                                .get("academicYear")) - 1)))
                .getDicValue()
                .concat(dictionaryMapper
                        .selectOne(new QueryWrapper<Dictionary>()
                                .lambda()
                                .eq(Dictionary::getLabel, "semester")
                                .eq(Dictionary::getDicCode, String.valueOf((ExamSemesterCalculatorUtil
                                        .getYearSemester(extracurricularScoreInfo.getStudentCode().toString(), extracurricularScoreInfo.getYear(), extracurricularScoreInfo.getSemester())
                                        .get("semester")) - 1)))
                        .getDicValue()));

        return basicInfo;
    }

    /**
     * @param extracurricularScoreInfos
     * @return 根据传入的课程组数据，进行填充三个维度的计算结果 ExtracurricularSumCalc
     */
    private ExtracurricularSumCalc fillExtracurricularDimensionDataByExtracurricularScoreInfos(List<ExtracurricularScoreInfo> extracurricularScoreInfos) {

        ExtracurricularSumCalc extracurricularSumCalc = new ExtracurricularSumCalc();

        extracurricularScoreInfos.forEach(extracurricularScoreInfo -> {
            //5 先计算总成绩
            extracurricularSumCalc.setOverallGrade(Optional.ofNullable(extracurricularSumCalc.getOverallGrade()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            //1 找到对应的活动信息
            if (extracurricularScoreInfo.getActivityCode() == null) {
                return;
            }
            ExtracurricularInfo extracurricularInfo = extracurricularInfoMapper.selectOne(new QueryWrapper<ExtracurricularInfo>().lambda().eq(ExtracurricularInfo::getActivityCode, extracurricularScoreInfo.getActivityCode()));
            if (extracurricularInfo == null) {
                return;
            }
            //2 根据第一维度对应属性
            String dimensionOne = extracurricularInfo.getActivityObjective();
            if (Objects.equals(dimensionOne, "理想信念")) {
                extracurricularSumCalc.setIdealsBeliefs(Optional.ofNullable(extracurricularSumCalc.getIdealsBeliefs()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionOne, "实践服务")) {
                extracurricularSumCalc.setPracticalService(Optional.ofNullable(extracurricularSumCalc.getPracticalService()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionOne, "文化艺术")) {
                extracurricularSumCalc.setLiteratureArt(Optional.ofNullable(extracurricularSumCalc.getLiteratureArt()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionOne, "学术科技")) {
                extracurricularSumCalc.setAcademicTechnology(Optional.ofNullable(extracurricularSumCalc.getAcademicTechnology()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionOne, "社会工作")) {
                extracurricularSumCalc.setSocialWork(Optional.ofNullable(extracurricularSumCalc.getSocialWork()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionOne, "体育素质")) {
                extracurricularSumCalc.setPhysicalFitness(Optional.ofNullable(extracurricularSumCalc.getPhysicalFitness()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            }
            //3 第二维度
            String dimensionTwo = extracurricularInfo.getActivityCategory();
            if (Objects.equals(dimensionTwo, "学生组织")) {
                extracurricularSumCalc.setStudentOrganization(Optional.ofNullable(extracurricularSumCalc.getStudentOrganization()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionTwo, "评奖评优")) {
                extracurricularSumCalc.setAwardsHonors(Optional.ofNullable(extracurricularSumCalc.getAwardsHonors()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionTwo, "活动竞赛")) {
                extracurricularSumCalc.setActivitiesCompetitions(Optional.ofNullable(extracurricularSumCalc.getActivitiesCompetitions()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            }
            //4 第三维度
            String dimensionThree = extracurricularInfo.getActivityLevel();
            if (Objects.equals(dimensionThree, "院级")) {
                extracurricularSumCalc.setCollegeLevel(Optional.ofNullable(extracurricularSumCalc.getCollegeLevel()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionThree, "校级")) {
                extracurricularSumCalc.setUniversityLevel(Optional.ofNullable(extracurricularSumCalc.getUniversityLevel()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionThree, "省市级")) {
                extracurricularSumCalc.setProvincialLevel(Optional.ofNullable(extracurricularSumCalc.getProvincialLevel()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            } else if (Objects.equals(dimensionThree, "国家级")) {
                extracurricularSumCalc.setNationalLevel(Optional.ofNullable(extracurricularSumCalc.getNationalLevel()).orElse(BigDecimal.ZERO).add(extracurricularScoreInfo.getScore()));
            }

        });
        return extracurricularSumCalc;
    }

    /**
     * @param infos
     * @return 每个学期的封装为一个List<ExtracurricularScoreInfo>，共八个
     * @atttion 可能有的list长度为0
     */
    private List<List<ExtracurricularScoreInfo>> divideBySemester(List<ExtracurricularScoreInfo> infos) {
        List<List<ExtracurricularScoreInfo>> yearSemester = new ArrayList<>();
        String studentCode = String.valueOf(infos.get(0).getStudentCode());
        Integer enrollment = Integer.valueOf("20" + studentCode.substring(0, 2));
        //1 按四个学年划分
        for (int i = 0; i < 4; i++) {
            List<ExtracurricularScoreInfo> springSemester = new ArrayList<>();
            List<ExtracurricularScoreInfo> autumnSemester = new ArrayList<>();

            //2 找出和学年i相对应的数据
            for (ExtracurricularScoreInfo info : infos) {
                //2.1 对应学年的上半学期
                if (info.getYear() - enrollment == i && Objects.equals(info.getSemester(), "秋季学期")) {
                    autumnSemester.add(info);
                }//2.2. 对应学年的下半学期
                else if (info.getYear() - enrollment == i + 1 && Objects.equals(info.getSemester(), "春季学期")) {
                    springSemester.add(info);
                }
            }
            //3 先填充上半学期后填充下班学习
            yearSemester.add(autumnSemester);
            yearSemester.add(springSemester);

        }
        return yearSemester;
    }


    public static double sumProperties(Object entity) {
        double sum = 0.0;

        // 获取实体类的所有字段
        Field[] fields = entity.getClass().getDeclaredFields();

        // 遍历字段并累加求和
        for (Field field : fields) {
            // 设置字段为可访问，以便获取其值
            field.setAccessible(true);

            // 判断字段类型并进行累加
            if (field.getType() == double.class || field.getType() == Double.class) {
                try {
                    Double value = (Double) field.get(entity);
                    sum += value;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            // 其他数据类型可以根据需要进行扩展

            // 恢复字段的访问性为默认状态
            field.setAccessible(false);
        }

        return sum;
    }
}




